feat(Chat): add @ file suggestions to input#27
Merged
Conversation
File Suggestions For `@` Mentions In Chat Input
Summary:
Add file-path suggestions to the chat input when the active token matches `@` followed by at least one non-whitespace character. Show suggestions below the input, allow `↑`/`↓` navigation, and on `Tab` replace the active `@query` token with the selected file path plus one trailing space. Use `ripgrep` first to gather project files, with a Node.js recursive fallback similar to `grepSearch()`.
Key Changes:
- Update `src/components/Chat/Input.tsx` to:
- keep owning the input string and reset/remount behavior for `TextInput`
- detect file suggestion mode from the active token using `(^|\s)@\S+`
- render `FileSuggestions` only when slash-command mode is not active
- apply the callback result from `FileSuggestions` by replacing the input value and remounting `TextInput`
- Add `src/components/Chat/FileSuggestions.tsx` to own:
- extraction of the active `@query` from the provided input value
- project file discovery
- filtering and focused-index navigation
- `Tab` confirmation
- rendering the suggestion list below the input with at most `5` visible options
- Keep slash command behavior unchanged:
- if input starts with `/`, continue rendering `CommandMenu`
- file suggestions do not appear while slash-command mode is active
- `Enter` continues to submit the input normally; it does not confirm file suggestions
- Implement file discovery inside `FileSuggestions.tsx` using:
- first choice: `rg --files` from `process.cwd()`
- fallback: recursive `readdirSync(..., { withFileTypes: true })`
- normalization to relative paths with `/` separators
- include hidden files/directories in suggestions
- exclude only `.git` from the fallback traversal
- Keep matching simple and case-insensitive against the path text after `@`.
- Have `FileSuggestions` call `onSelect(nextInput: string)` so it returns the fully rewritten input string, including the trailing space, instead of only the raw file path.
- Do not support `Esc` dismissal for file suggestions; the list should open and close solely based on the current input text and normal editing.
Public Interfaces / Behavior:
- No CLI/API changes.
- New TUI behavior:
- typing `@` followed by any non-whitespace character in the active token opens file suggestions below the input
- `↑`/`↓` move focus through suggestions
- `Tab` inserts the focused file path into the input and appends one space
- `Enter` still submits the current input and does not confirm the suggestion list
- suggestions disappear automatically when the active token no longer matches `@\S+` or when no files match
Test Plan:
- Add `Input` tests for:
- no file suggestions for plain text or bare `@`
- file suggestions appear for `@s`, `@1`, `@_`, or `@foo-bar`
- slash command suggestions still win for leading `/`
- `Tab` inserts the focused file path and appends one trailing space
- insertion replaces only the active trailing `@query` token and preserves surrounding text
- `Enter` still submits while file suggestions are visible
- `Backspace` updates or closes file suggestions correctly
- disabled input ignores file suggestion interactions
- Add `FileSuggestions` tests for:
- `rg --files` success path
- fallback to Node.js traversal when `rg` fails
- fallback excludes `.git` but includes other hidden paths
- case-insensitive filtering
- focused-index movement and `Tab` selection behavior
- max visible option count is `5`
Assumptions:
- Suggestion source is project file paths relative to the current working directory.
- `ripgrep` is optional; the feature must work without it via the Node.js fallback.
- `FileSuggestions` will contain both its own logic and rendering; no separate helper module is introduced initially.
- The input remains synchronized by remounting `TextInput` with a refreshed `defaultValue` after a selection is inserted.
In `FileSuggestions.tsx`, `isMounted` only prevents this sequence: 1. component starts async file loading 2. component unmounts 3. async load resolves 4. `setFilePaths(...)` runs after unmount In modern React, that usually won’t break correctness here, but it can still be noisy and it is unnecessary work. Since this effect is a one-shot async read, the guard is a simple way to avoid updating dead state. That said, for this specific component: - there is no subscription to clean up - there is no retry loop - there is no race between multiple concurrent requests - the only real concern is post-unmount setState So if you want to simplify, removing `isMounted` is reasonable. The behavior of the feature would still be fine. I’d only keep it if you want to be explicit about ignoring late async results.
Codecov Report✅ All modified and coverable lines are covered by tests.
🚀 New features to boost your workflow:
|
@ file suggestions to input
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What is the motivation for this pull request?
Add file suggestions in the chat input so users can reference project files quickly with
@mentions in the TUI.plan.md
What is the current behavior?
The chat input supports slash-command suggestions, but there is no
@mention autocomplete for files.What is the new behavior?
@followed by non-whitespace text.rg --files --hidden -g "!**/.git/**"to load project files with a Node.js directory-walk fallback.UpandDownto change the focused file suggestion.Tab, replacing the active mention token and appending a trailing space.Enteras submit.grepSearchcleanup changingresults.length === 0to!results.length.Checklist: